<?php

/**
 * 
 * ClientEngage: ClientEngage Visitor Voice (http://www.clientengage.com)
 * Copyright 2012, ClientEngage (http://www.clientengage.com)
 *
 * You must have purchased a valid license from CodeCanyon in order to have 
 * the permission to use this file.
 * 
 * You may only use this file according to the respective licensing terms 
 * you agreed to when purchasing this item on CodeCanyon.
 * 
 * 
 * 
 *
 * @author          ClientEngage <contact@clientengage.com>
 * @copyright       Copyright 2013, ClientEngage (http://www.clientengage.com)
 * @link            http://www.clientengage.com ClientEngage
 * @since           ClientEngage - Visitor Voice v 1.0
 * 
 */
App::uses('AppController', 'Controller');

/**
 * Visitorvoices Controller
 *
 * @property Visitorvoice $Visitorvoice
 */
class VisitorvoicesController extends AppController
{

    public $name = 'Visitorvoices';

    /**
     *
     * @var array Helpers to be loaded
     */
    public $helpers = array('Jqplot');

    /**
     * Processes one cache-regeneration batch
     * @param type $visitorform_id
     * @return string Json object containing the number of remaining items
     */
    public function admin_process_responsecache($visitorform_id = null)
    {
        $this->autoRender = false;
        $this->response->type('json');

        if ($this->request->is('put'))
        {
            $this->Visitorvoice->regenerateResponseCache($visitorform_id);
            return json_encode(array(
                'remaining' => $this->Visitorvoice->countPendingResponseCache($visitorform_id)
            ));
        }
    }

    /**
     * Action for the cache-regeneration
     * @param uuid $visitorform_id
     */
    public function admin_generate_responsecache($visitorform_id = null)
    {
        $this->set('title_for_layout', __('Re-Generate Response Cache'));
        $this->set('pendingCount', $this->Visitorvoice->countPendingResponseCache($visitorform_id));
        $this->set('visitorform_id', $visitorform_id);
    }

    /**
     * Action for rendering the paginated response list
     * @param uuid $visitorform_id
     */
    public function admin_responses($visitorform_id = null)
    {
        $this->set('title_for_layout', __('Response List'));

        $this->Visitorvoice->recursive = -1;

        $this->paginate = array(
            'limit' => 25,
            'order' => array(
                'Visitorvoice.id' => 'desc'
            ),
            'conditions' => array(
                'Visitorvoice.visitorform_id' => $visitorform_id
            ),
            'contain' => array(
                'Response' => array('FieldOption', 'SelectedOption')
            )
        );

        $visitorform = $this->Visitorvoice->Visitorform->find('first', array('conditions' => array('Visitorform.id' => $visitorform_id), 'contain' => array('Field' => 'FieldOption')));
        $visitorvoices = $this->paginate('Visitorvoice');
        $viewData = $this->__formatResponses($visitorform, $visitorvoices);

        $this->set('visitorform', $visitorform);
        $this->set('viewData', $viewData);
    }

    /**
     * Action for rendering the statistics dashboard of a visitor form
     * @param uuid $visitorform_id
     */
    public function admin_statistics($visitorform_id = null)
    {
        if ($this->Visitorvoice->checkResponseCacheIncomplete($visitorform_id))
            $this->redirect(array('action' => 'generate_responsecache', $visitorform_id));

        $this->set('title_for_layout', __('Response Statistics'));

        $this->Visitorvoice->recursive = -1;
        $formCacheKey = 'Visitorform_' . md5($visitorform_id);
        if (($visitorform = Cache::read($formCacheKey)) === false)
        {
            $visitorform = $this->Visitorvoice->Visitorform->find('first', array('conditions' => array('Visitorform.id' => $visitorform_id), 'contain' => array('Field' => array('fields' => array('id', 'title', 'visitorform_id', 'type', 'position', 'required'), 'FieldOption' => array('fields' => array('id', 'title', 'position'))))));
            if ($visitorform)
                Cache::write($formCacheKey, $visitorform);
        }

        $statsCacheKey = 'Statistics_' . md5($visitorform_id);
        if (($viewData = Cache::read($statsCacheKey)) === false)
        {
            $visitorvoices = $this->Visitorvoice->getResponseData($visitorform_id);

            $viewData = $this->__calculateStatistics($visitorform, $visitorvoices);
            if ($viewData)
                Cache::write($statsCacheKey, $viewData);
        }

        $this->set('visitorform', $visitorform);
        $this->set('viewData', $viewData);
    }

    /**
     * Formats the responses and form for futher statistical processing
     * @param array $visitorform
     * @param array $visitorvoices
     * @return array Formatted response data
     */
    private function __calculateStatistics(array $visitorform, array &$visitorvoices)
    {
        $stats = array();

        // Create field-template
        foreach ($visitorform['Field'] as $field)
        {
            $stats[$field['id']]['Field'] = $field;

            if (!empty($field['FieldOption']))
            {
                $stats[$field['id']]['FieldOption'] = array();
                foreach ($field['FieldOption'] as $opt)
                {
                    // Holds the option counters (multiple & single)
                    $stats[$field['id']]['FieldOption'][$opt['id']] = array('title' => $opt['title'], 'count' => 0);
                }
            }
            else
            {
                $stats[$field['id']]['values'] = array(); // holds an array of values for input fields
            }
        }

        // Manually add referer
        $stats['Referer']['Field'] = array('title' => __('Referers'), 'type' => 'textshort');
        $stats['Referer']['values'] = array();

        // Loop  field-templates and incrementally fill with data
        foreach ($stats as $key => $fieldStat)
        {
            if (isset($fieldStat['values'])) // process input fields
            {
                foreach ($visitorvoices as $visitorvoice)
                {
                    if (is_array($visitorvoice['Response']))
                        foreach ($visitorvoice['Response'] as $response)
                        {
                            if ($response['field_id'] == $key && $response['value'] !== null)
                                $stats[$key]['values'][] = $response['value']; // add input values
                        }
                }
            }
            else // multiple & single select fields
            {
                foreach ($visitorvoices as $visitorvoice)
                {
                    if (is_array($visitorvoice['Response']))
                    {
                        foreach ($visitorvoice['Response'] as $response)
                        {
                            if ($response['field_id'] == $key)
                            {
                                foreach ($response['FieldOption'] as $opt) // multi incr.
                                    $stats[$key]['FieldOption'][$opt['id']]['count']++;

                                if (isset($stats[$key]['FieldOption'][$response['field_option_id']])) // single incr.
                                    $stats[$key]['FieldOption'][$response['field_option_id']]['count']++;
                            }
                        }
                    }
                }
            }
        }

        // Manually add referers
        foreach ($visitorvoices as $visitorvoice)
        {
            $stats['Referer']['values'][] = $visitorvoice['Visitorvoice']['referer'];
        }

        $visitorvoices = null;
        unset($visitorvoices);

        return array('count' => $visitorform['Visitorform']['visitorvoice_count'], 'Statistics' => $stats);
    }

    /**
     * Action for the download of all responses in XLS or CSV formats
     * @param uuid $visitorform_id
     */
    public function admin_export($visitorform_id = null, $type = 'xls')
    {
        if ($this->Visitorvoice->checkResponseCacheIncomplete($visitorform_id))
            $this->redirect(array('action' => 'generate_responsecache', $visitorform_id));

        $this->autoRender = false;
        $this->Visitorvoice->recursive = -1;

        $formCacheKey = 'Visitorform_' . md5($visitorform_id);
        if (($visitorform = Cache::read($formCacheKey)) === false)
        {
            $visitorform = $this->Visitorvoice->Visitorform->find('first', array('conditions' => array('Visitorform.id' => $visitorform_id), 'contain' => array('Field' => array('fields' => array('id', 'title', 'visitorform_id', 'type', 'position', 'required'), 'FieldOption' => array('fields' => array('id', 'title', 'position'))))));
            if ($visitorform)
                Cache::write($formCacheKey, $visitorform);
        }

        $statsCacheKey = 'FullTable_' . md5($visitorform_id);
        if (($viewData = Cache::read($statsCacheKey)) === false)
        {
            $visitorvoices = $this->Visitorvoice->getResponseData($visitorform_id);

            $viewData = $this->__formatResponses($visitorform, $visitorvoices);
            if ($viewData)
                Cache::write($statsCacheKey, $viewData);
        }

        $excelData = array();
        $headerRow = array();
        foreach ($viewData['fields'] as $k => $field)
            $headerRow[$k] = $field['title'];
        $excelData[] = $headerRow;


        foreach ($viewData['data'] as $data)
        {
            $row = array();
            foreach ($data as $k => $d)
                $row[$k] = $d;
            $excelData[] = $row;
        }

        if ($type == 'xls')
        {
            App::import('Vendor', 'PHPExcel', array('file' => 'PHPExcel/php-excel.class.php'));
            $xls = new Excel_XML('UTF-8', true, 'ResponseTable');

            $this->response->header('Content-disposition', 'attachment; filename=Responses.xls');
            $this->response->header('Content-type', 'application/force-download');
            $xls->addArray($excelData);
            $xls->generateXML('Responses');
        }
        else if ($type == 'csv')
        {
            $csvTitles = array();
            $csvData = array();
            $i = 0;
            foreach ($excelData as $eRow)
            {
                if ($i == 0)
                    $csvTitles = array_values($eRow);
                else
                    $csvData[] = array_values($eRow);

                $i++;
            }

            App::import('Vendor', 'parseCSV', array('file' => 'parseCSV/parsecsv.lib.php'));
            $csvRenderer = new parseCSV();
            $csvRenderer->input_encoding = $csvRenderer->output_encoding = 'UTF-8';

            $this->response->header('Content-disposition', 'attachment; filename=Responses.csv');
            $this->response->header('Content-type', 'application/force-download');

            $csvRenderer->output(true, 'Responses.csv', $csvData, $csvTitles);
        }
        else
        {
            throw new InvalidArgumentException();
        }
    }

    /**
     * Formats responses and forms into a flat array of "[n].field_id => data"
     * @param array $visitorform
     * @param array $visitorvoices
     * @return array Formatted data
     */
    private function __formatResponses(array $visitorform, array $visitorvoices)
    {
        // Contains all fields and labels
        $rowTemplate = array();
        $rowTemplate['ID'] = array('position' => -22, 'title' => __('UUID'));
        $rowTemplate['UniqueID'] = array('position' => -21, 'title' => __('Unique ID'));

        // Add question templates
        foreach ($visitorform['Field'] as $field)
        {
            if (in_array($field['type'], array('textshort', 'textlong', 'checkbox', 'rating', 'slider', 'spinner', 'date')))
            {
                $rowTemplate[$field['id']] = array('position' => $field['position'], 'title' => $field['title'], 'type' => $field['type']);
            }
            if (in_array($field['type'], array('select', 'radio')))
            {
                $rowTemplate[$field['id']] = array('position' => $field['position'], 'title' => $field['title'], 'type' => $field['type']);
            }
            if (in_array($field['type'], array('selectmultiple', 'checkboxmultiple')))
            {
                foreach ($field['FieldOption'] as $selected)
                {
                    $rowTemplate[$selected['id']] = array('position' => $field['position'], 'inner_position' => $selected['position'], 'title' => $field['title'] . ' <br />[' . $selected['title'] . ']', 'type' => $field['type']);
                }
            }
        }

        // Add meta data templates
        $rowTemplate = $rowTemplate + array(
            'DateTimeStarted' => array('position' => -20, 'title' => __('Started Date')),
            'DateTimeSubmitted' => array('position' => -19, 'title' => __('Submitted Date')),
            'Duration' => array('position' => -18, 'title' => __('Duration')),
            'Referer' => array('position' => -17, 'title' => __('Referer Url')),
            'UserAgent' => array('position' => -16, 'title' => __('User Agent')),
        );


        // Contains unsorted response data
        $allResponses = array();
        foreach ($visitorvoices as $voice)
        {
            $row = array();
            $row['ID'] = $voice['Visitorvoice']['id'];
            $row['UniqueID'] = $voice['Visitorvoice']['unique_id'];

            if (is_array($voice['Response']))
                foreach ($voice['Response'] as $response)
                {
                    if (!empty($response['FieldOption']))
                        foreach ($response['FieldOption'] as $selected)
                            $row[$selected['id']] = 1;
                    if (!empty($response['SelectedOption']))
                        $row[$response['field_id']] = $response['SelectedOption']['title'];
                    if (isset($response['value']) && $response['value'] != '')
                        $row[$response['field_id']] = $response['value'];
                }
            $row['DateTimeStarted'] = $voice['Visitorvoice']['started'];
            $row['DateTimeSubmitted'] = $voice['Visitorvoice']['created'];
            $row['Duration'] = null;
            if (strtotime($row['DateTimeStarted']) !== false && strtotime($row['DateTimeSubmitted']) !== false)
            {
                $diff = strtotime($row['DateTimeSubmitted']) - strtotime($row['DateTimeStarted']);
                $row['Duration'] = gmdate("H:i:s", $diff);
            }

            $row['Referer'] = $voice['Visitorvoice']['referer'];
            $row['UserAgent'] = $voice['Visitorvoice']['useragent'];

            $allResponses[] = $row;
        }

        // Contains final response data sorted by fields
        $formatted = array();
        foreach ($allResponses as $response)
        {
            $nRow = array();
            foreach ($rowTemplate as $id => $fieldDetails)
            {
                if (array_key_exists($id, $response))
                    $nRow[$id] = $response[$id];
                else
                    $nRow[$id] = null;
            }

            $formatted[] = $nRow;
        }

        return array('fields' => $rowTemplate, 'data' => $formatted);
    }

    /**
     * View method for showing individual responses
     *
     * @throws NotFoundException
     * @param uuid $id
     * @return void
     */
    public function admin_view($id = null)
    {
        $this->set('title_for_layout', __('Individual Response'));

        $this->Visitorvoice->id = $id;
        if (!$this->Visitorvoice->exists())
        {
            throw new NotFoundException(__('Invalid visitorvoice'));
        }
        $this->set('neighbours', $this->Visitorvoice->find('neighbors', array(
                    'field' => 'id', 'value' => $id,
                    'conditions' => array('Visitorvoice.visitorform_id' => $this->Visitorvoice->field('visitorform_id')),
                    'order' => 'Visitorvoice.id DESC')));

        $this->set('first', $this->Visitorvoice->find('first', array(
                    'fields' => array('id'),
                    'limit' => 1,
                    'conditions' => array('Visitorvoice.visitorform_id' => $this->Visitorvoice->field('visitorform_id')),
                    'order' => 'Visitorvoice.id DESC')));
        $this->set('last', $this->Visitorvoice->find('first', array(
                    'fields' => array('id'),
                    'limit' => 1,
                    'conditions' => array('Visitorvoice.visitorform_id' => $this->Visitorvoice->field('visitorform_id')),
                    'order' => 'Visitorvoice.id ASC')));

        $data = $this->Visitorvoice->find('first', array('conditions' => array('Visitorvoice.id' => $id), 'contain' => array('Visitorform' => array('Field' => 'FieldOption'), 'Response' => array('FieldOption', 'SelectedOption'))));

        $orderedResponses = array();
        foreach ($data['Visitorform']['Field'] as $field)
        {
            foreach ($data['Response'] as $response)
            {
                if ($response['field_id'] == $field['id'])
                    $orderedResponses[] = array('Field' => $field, 'Response' => $response);
            }
        }

        $this->set('responses', $orderedResponses);
        $this->set('visitorvoice', $data);
    }

    /**
     * Delete method for individual responses
     *
     * @throws MethodNotAllowedException
     * @throws NotFoundException
     * @param string $id
     * @return void
     */
    public function admin_delete($id = null)
    {
        if (!$this->request->is('post'))
        {
            throw new MethodNotAllowedException();
        }
        $this->Visitorvoice->id = $id;
        if (!$this->Visitorvoice->exists())
        {
            throw new NotFoundException(__('Invalid Visitor Voice'));
        }

        $visitorform_id = $this->Visitorvoice->field('visitorform_id');
        if ($this->Visitorvoice->delete())
        {
            $this->Session->setFlash(__('Visitor Voice deleted'), Flash::Success);
            $this->redirect(array('action' => 'responses', $visitorform_id));
        }
        $this->Session->setFlash(__('Visitor Voice was not deleted'), Flash::Error);
        $this->redirect($this->referer());
    }

    /**
     * Delete method for selected responses
     * @throws MethodNotAllowedException
     */
    public function admin_deleteselected()
    {
        if (!$this->request->is('post') || !isset($this->request->data['Meta']['del']))
        {
            throw new MethodNotAllowedException();
        }

        $toDelete = $this->request->data['Meta']['del'];
        $visitorform_id = $this->request->data['Meta']['visitorform_id'];

        if ($this->Visitorvoice->deleteAll(array('Visitorvoice.id' => $toDelete), true, true))
        {
            $this->Session->setFlash(String::insert(__n('You have successfully deleted :count visitor voice', 'You have successfully deleted :count visitor voices', count($toDelete)), array('count' => count($toDelete))), Flash::Success);
        }
        else
        {
            $this->Session->setFlash(__('The delete operation could not be completed'), Flash::Error);
        }
        $this->redirect(array('action' => 'responses', $visitorform_id));
    }

    /**
     * Delete method for all responses belonging to the passed visitor form
     * @param uuid $visitorform_id
     * @throws MethodNotAllowedException
     */
    public function admin_deleteall($visitorform_id = null)
    {
        if (!$this->request->is('post'))
        {
            throw new MethodNotAllowedException();
        }

        if ($this->Visitorvoice->deleteAll(array('Visitorvoice.visitorform_id' => $visitorform_id), true, true))
        {
            $this->Session->setFlash(__('You have successfully deleted all responses belonging to the respective visitor form'), Flash::Success);
        }
        else
        {
            $this->Session->setFlash(__('The delete operation could not be completed'), Flash::Error);
        }
        $this->redirect(array('action' => 'responses', $visitorform_id));
    }

}
